package it.antonio.ilpizze.swing.session;

import it.antonio.ilpizze.swing.SwingException;

import java.awt.Component;
import java.awt.Container;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JFrame;

public class SessionStorage implements Serializable {

	private static final long serialVersionUID = 1L;
	private static final File file = new File("SessionStorage.dat");
	private SessionStateCreator creator;
	
	public SessionStorage(SessionStateCreator creator) {
		super();
		this.creator = creator;
	}

	public void save(JFrame frame) {
		
		States states = new States();
		String name = JFrame.class.getSimpleName();
		buildComponentTree(frame, name, states);
		
		try {
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);

            oos.writeObject(states);

            oos.close();
        } catch(Exception e){
        	throw new SwingException(e);
        }
	}

	private void buildComponentTree(Component component, String name, States states) {
		SessionState<Component> state = creator.create(component.getClass());
		state.save(component);
		states.put(name, state);
		if (component instanceof Container) {
			Container container = (Container) component;
			for (int i = 0; i < container.getComponentCount(); i++) {
				Component child = container.getComponent(i);
				String childName = name(name, child, i);
				buildComponentTree(child, childName, states);
			}
		}
	
	}

	public void restore(JFrame frame) {
		States states = null;
		
		try {
			if(file.exists()){
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
			    states = (States) ois.readObject();	
			}
		} catch(Exception e){
        	throw new SwingException(e);
        }
		
		if(states == null){
			return;
		}
		frame.setResizable(true);
		String name = JFrame.class.getSimpleName();
		buildComponent(frame, name, states);
		
		
	}

	private void buildComponent(Component component, String name, States states) {
		
		SessionState<Component> state = states.get(name);
		if(state == null){
			return;
		}
		state.restore(component);
		
		if (component instanceof Container) {
			Container container = (Container) component;
			for (int i = 0; i < container.getComponentCount(); i++) {
				Component child = container.getComponent(i);
				String childName = name(name, child, i);
				buildComponent(child, childName, states);
			}
		}
	}

	private String name(String parentName, Component c, int childIndex){
		return (parentName != null) ? parentName + "." + c.getClass().getSimpleName()+"_" +childIndex : c.getClass().getSimpleName(); 
	}
	
	public class States implements Serializable {

		private static final long serialVersionUID = 1L;
		Map<String, SessionState<Component>> states = new HashMap<String, SessionState<Component>>();

		public SessionState<Component> get(String name) {
			return states.get(name);
		}

		public void put(String name, SessionState<Component> c) {
			states.put(name, c);
		}

	}

	

}
